﻿#include "Session.h"
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp> 
#include <boost/asio/buffer.hpp>
#include <boost/asio/steady_timer.hpp>  
#include <memory> 
#include "AsioServer.h"
#include "../base/EventDispatcher.h"
#include "../protobuf/cmd.pb.h"
#include "../protobuf/scene.pb.h"
#include "../Log.h"

const char LOG_NAME[] = "Session";

using namespace  std;
using namespace  boost;
using namespace boost::asio;
using boost::asio::spawn;
using std::placeholders::_1;
using namespace  Base;
Session::Session(AsioServer* server,int id) :
_strand(server->io),
_socket(server->io),
_server(server),
_id(id)
{
}

void Session::SleepMS(unsigned int ms, yield_context yield)
{
	steady_timer timer(_strand.get_io_service());
	timer.expires_from_now(chrono::milliseconds(ms));
	boost::system::error_code ec;
	timer.async_wait(yield[ec]);
}

void Session::Disconnect()
{
	if (!_isConnected)
		return;
	boost::system::error_code ec;
	_socket.close(ec);
	_isConnected = false;
}

void Session::Run()
{
	LOG_INFOF(FMT("Session id=%d start work") % this->_id);
	_isConnected = true;
	spawn(_strand, bind(&Session::LoopRead, this, _1));
	spawn(_strand, bind(&Session::LoopWrite, this, _1));
}

void Session::LoopRead(yield_context yield)
{
	while (_isConnected)
	{
		int len = 0;
		system::error_code ec;
		std::size_t _len = async_read(_socket, buffer(&len, sizeof(int)), yield[ec]);
		if (_len < 4 || len <= 0)break;
		std::vector<char> buf;
		//cout << "recv len=" << len << endl;
		buf.resize(len);
		int len2 = async_read(_socket, buffer(&buf[0], len), yield[ec]);
		if (len2 <= 0)break;
		if (len2 != len)break;
		cmd _cmd;
		_cmd.ParseFromArray(&buf[0], buf.size());
 
		LOG_INFOF(FMT("recv : cmd  name= %s") % _cmd.name());
		//通知主线程处理网络消息
		EventDispatcher::GetInstance()->PostEventStatic(_cmd.name(), _cmd.data());
	}
	LOG_INFOF(FMT("dis connected id=%d") % this->_id );
	Disconnect();
}

void Session::LoopWrite(yield_context yield)
{
	while (true)
	{
		scene::scene_req_move sce;
		sce.set_x(10);
		sce.set_y(20);

		cmd _cmd;
		_cmd.set_name("hello proto");
		_cmd.set_data(sce.SerializeAsString());

		string s = _cmd.SerializeAsString();

		unsigned int len = s.size() + 1;
		vector <char> buf;
		for (int ii = 0; ii < sizeof(unsigned int); ii++)
		{
			char  *addr = (char*)(&len);
			buf.push_back(*(addr + ii));
		}
		for (int ii = 0; ii < s.size(); ii++)
		{
			buf.push_back(s.at(ii));
		}
		buf.push_back('\0');

		boost::system::error_code ec;
		async_write(this->_socket, buffer((char*)(&(buf[0])), buf.size()), yield[ec]);
		{
			SleepMS(30, yield);
		}
		continue;
		{
			Disconnect();
			break;
		}
	}

}